//=======================================================
/**
 * @description 小程序应用页面代理对象工厂
 * @author Brave Chan on 2019.5
 * @version 1.0.3
 */
//=======================================================
import {
  isFunction,
  assignObjExcept,
  getSysId
} from '../utils/util';
import { execAry, execAsyncList } from '../utils/execList';
import {
  combineGlobalData,
  clearOriginData
} from './beconst';
import {
  PAGE_TYPE
} from '../constant/nodeType';
import {
  be_mountMethods,
  be_invokeOriginPares,
  be_invokeInitVMP,
  be_invokeParse,
  be_invokeDecorate,
  be_invokeWash,
  be_invokeDestroyVMP,
  be_invokeOnShow,
  be_invokeOnHide
} from './BEModules';
import Log from '../tools/BELog';
import be_opt from '../constant/be_opt';
import { saveExecList, loadExecList } from './beGlobal';
//============================================================
/*
{
  data() {
    text: "This is page data."
  },
  created() {}, // 相当于onLoad
  onShow() {},
  ready() {}, // 相当于onReady
  onHide() {},
  destroyed() {}, // 相当于onUnload
  methods: {},
  methodAreas: []
}
*/
//============================================================
// parse 阶段
function originParse(origin, page) {
  let data = combineGlobalData(origin.data);

  // 调用需要parse阶段处理的模块
  be_invokeOriginPares(page, origin, PAGE_TYPE);

  page.data = data;
}

// 预初始化
function preInit(origin, page) {
  page._beID = getSysId();
  page.__initialized__ = false;

  page._beNodeType = PAGE_TYPE;
}

// 绑定方法
function bindMethods(origin, page) {
  // methods
  page._methods = Object.assign({}, origin.methods || {});

  // methodAreas
  const areas = origin.methodAreas || [];
  let len = areas.length;

  let fns, entries;
  while (len--) {
    fns = areas[len];
    entries = Object.entries(fns);
    for (const [fnName, fn] of entries) {
      if (typeof fn === 'function') {
        page._methods[fnName] = fn;
      }
    }
  }
}

// 包装onLoad
function packLoad(origin, page) {
  page.onLoad = (function (fn) {
    return function (options) {
      if (!this) {
        Log.error('In Page onLoad, can not get the "this" obj!!', this);
        if (be_opt.debug) {
          throw new Error('In Page onLoad, can not get the "this" obj!!');
        }
      } else {
        be_mountMethods(this);
        be_invokeInitVMP(this);
        be_invokeDecorate(this, this._be_vmp);
        be_invokeParse(this, this._be_vmp);
      }
      if (isFunction(fn)) {
        fn.call(this, options);
      }

      const execList = loadExecList(this._be_init_execs);
      // this._be_init_execs = null;

      // 执行队列之前，让提交的属性立即生效
      if (typeof this.validateNow === 'function') {
        this.validateNow();
      }

      // 执行预定函数队列
      if (Array.isArray(execList)) {
        execAry(this, execList);
      }

      // 执行含有异步的预定函数队列
      if (execList && execList.__isAsync) {
        execAsyncList(this, execList);
      }
    };
  })(origin.created);
}

// 包装onUnload
function packUnload(origin, page) {
  page.onUnload = (function (fn) {
    return function () {
      if (this) {
        be_invokeWash(this, this._be_vmp);
        be_invokeDestroyVMP(this, this._be_vmp);
      }
      if (isFunction(fn)) {
        fn.call(this);
      }
    };
  })(origin.destroyed);
}

// 包装onReady
function packReady(origin, page) {
  page.onReady = (function(fn) {

    return function () {
      if (isFunction(fn)) {
        fn.call(this);
      }
    };
  })(origin.ready);
}

// 包装onShow
function packShow(origin, page) {
  page.onShow = (function (fn) {
    return function (options) {
      //when instance onShow, commit the props that collected during onHide be invoked.
      be_invokeOnShow(this, this._be_vmp);

      if (isFunction(fn)) {
        fn.call(this, options);
      }
    };
  })(origin.onShow);
}

// 包装onHide
function packHide(origin, page) {
  page.onHide = (function (fn) {
    return function () {
      // when instance onHide, pause the props validate.
      be_invokeOnHide(this, this._be_vmp);

      if (isFunction(fn)) {
        fn.call(this);
      }
    };
  })(origin.onHide)
}
//============================================================
/**
 * 页面代理对象工厂
 * @param {object} origin [required] 声明式开发对象
 * @returns {object} 适用于小程序Page()的对象
 */
export default function BEPage(origin = {}, execList = []) {
  const page = [
    originParse,
    preInit,
    bindMethods,
    packLoad,
    packUnload,
    packReady,
    packShow,
    packHide
  ].reduce(function (wPage, item) {
    item(origin, wPage);
    return wPage;
  }, {});

  if (execList && (Array.isArray(execList) || !!execList.__isAsync)) {
    page._be_init_execs = page._beID;
    saveExecList(page._beID, execList);
  }

  const result = assignObjExcept(page, origin, ['created', 'destroyed', 'onShow', 'onHide', 'onReady', 'data', 'methods', 'methodAreas']);

  clearOriginData(origin);
  origin = null;

  return result;
};
//=======================================================
